bitkeeper revision 1.1159.1.401 (41923739R6r2c-dNxHPSxOagRn-R3g)
authorcl349@freefall.cl.cam.ac.uk <cl349@freefall.cl.cam.ac.uk>
Wed, 10 Nov 2004 15:43:53 +0000 (15:43 +0000)
committercl349@freefall.cl.cam.ac.uk <cl349@freefall.cl.cam.ac.uk>
Wed, 10 Nov 2004 15:43:53 +0000 (15:43 +0000)
Setup cpu-local interrupt handline.
Add support for ipi event channels.

linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smpboot.c
linux-2.6.9-xen-sparse/arch/xen/i386/kernel/time.c
linux-2.6.9-xen-sparse/arch/xen/kernel/evtchn.c
linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h
xen/common/event_channel.c
xen/common/keyhandler.c
xen/include/public/event_channel.h
xen/include/xen/sched.h

index 1843479a42cfa8a7e77fe17f3b0a75f0f423b666..f492b5a5dba14e70dcbf9597e017db927342ce7f 100644 (file)
@@ -441,6 +441,32 @@ int cpucount;
 
 extern int cpu_idle(void);
 
+
+static irqreturn_t local_debug_interrupt(int irq, void *dev_id,
+                                        struct pt_regs *regs)
+{
+       xxprint("local_debug_interrupt\n");
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction local_irq_debug = {
+       local_debug_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "ldebug",
+       NULL, NULL
+};
+
+void local_setup_debug(void)
+{
+       int time_irq;
+
+       time_irq = bind_virq_to_irq(VIRQ_DEBUG);
+       (void)setup_irq(time_irq, &local_irq_debug);
+}
+
+
+extern void setup_misdirect_virq(void);
+extern void local_setup_timer(void);
+
 /*
  * Activate a secondary processor.
  */
@@ -455,29 +481,18 @@ int __init start_secondary(void *unused)
        smp_callin();
        while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
                rep_nop();
-#if 1
-       if (0) {
-               char *msg = "start_secondary\n";
-               char *msg2 = "delay2\n";
-               int timeout;
-               (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(msg), msg);
-               for (timeout = 0; timeout < 50000; timeout++) {
-                       udelay(100);
-                       if (timeout == 20000) {
-                               (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(msg2), msg2);
-                               timeout = 0;
-                       }
-               }
-       }
-       // enable_APIC_timer();
+       setup_misdirect_virq();
+       local_setup_timer();
+       local_setup_debug();    /* XXX */
+       local_irq_enable();
        /*
         * low-memory mappings have been cleared, flush them from
         * the local TLBs too.
         */
-       // local_flush_tlb();
+       local_flush_tlb();
        cpu_set(smp_processor_id(), cpu_online_map);
        wmb();
-       if (10) {
+       if (01) {
                char *msg2 = "delay2\n";
                int timeout;
                for (timeout = 0; timeout < 50000; timeout++) {
@@ -489,32 +504,6 @@ int __init start_secondary(void *unused)
                }
        }
        return cpu_idle();
-#else
-       /*
-        * Dont put anything before smp_callin(), SMP
-        * booting is too fragile that we want to limit the
-        * things done here to the most necessary things.
-        */
-       cpu_init();
-       smp_callin();
-       while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
-               rep_nop();
-       setup_secondary_APIC_clock();
-       if (nmi_watchdog == NMI_IO_APIC) {
-               disable_8259A_irq(0);
-               enable_NMI_through_LVT0(NULL);
-               enable_8259A_irq(0);
-       }
-       enable_APIC_timer();
-       /*
-        * low-memory mappings have been cleared, flush them from
-        * the local TLBs too.
-        */
-       local_flush_tlb();
-       cpu_set(smp_processor_id(), cpu_online_map);
-       wmb();
-       return cpu_idle();
-#endif
 }
 
 /*
index 3a7360245c3d7c472a8724634c585380817de083..e93d7b9b04ec72e439029f6b877dbfc08b1a255d 100644 (file)
@@ -702,6 +702,35 @@ void time_resume(void)
        last_update_from_xen = 0;
 }
 
+#ifdef CONFIG_SMP
+static irqreturn_t local_timer_interrupt(int irq, void *dev_id,
+                                        struct pt_regs *regs)
+{
+       static int xxx = 0;
+       if ((xxx++ % 100) == 0)
+               xxprint("local_timer_interrupt\n");
+
+       /* XXX add processed_system_time loop thingy */
+       if (regs)
+               update_process_times(user_mode(regs));
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction local_irq_timer = {
+       local_timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "ltimer",
+       NULL, NULL
+};
+
+void local_setup_timer(void)
+{
+       int time_irq;
+
+       time_irq = bind_virq_to_irq(VIRQ_TIMER);
+       (void)setup_irq(time_irq, &local_irq_timer);
+}
+#endif
+
 /*
  * /proc/sys/xen: This really belongs in another file. It can stay here for
  * now however.
index 018f7aeb926a01c6140596ab46a35f92727a2057..688816372c488b4a62a9de5f54c9f5272f1cdf25 100644 (file)
@@ -61,7 +61,11 @@ static int evtchn_to_irq[NR_EVENT_CHANNELS];
 static int irq_to_evtchn[NR_IRQS];
 
 /* IRQ <-> VIRQ mapping. */
-static int virq_to_irq[NR_VIRQS];
+DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]);
+
+#define NR_IPIS 8
+/* IRQ <-> IPI mapping. */
+DEFINE_PER_CPU(int, ipi_to_evtchn[NR_IPIS]);
 
 /* Reference counts for bindings to IRQs. */
 static int irq_bindcount[NR_IRQS];
@@ -141,10 +145,11 @@ int bind_virq_to_irq(int virq)
 {
     evtchn_op_t op;
     int evtchn, irq;
+    int cpu = smp_processor_id();
 
     spin_lock(&irq_mapping_update_lock);
 
-    if ( (irq = virq_to_irq[virq]) == -1 )
+    if ( (irq = per_cpu(virq_to_irq, cpu)[virq]) == -1 )
     {
         op.cmd              = EVTCHNOP_bind_virq;
         op.u.bind_virq.virq = virq;
@@ -156,7 +161,7 @@ int bind_virq_to_irq(int virq)
         evtchn_to_irq[evtchn] = irq;
         irq_to_evtchn[irq]    = evtchn;
 
-        virq_to_irq[virq] = irq;
+        per_cpu(virq_to_irq, cpu)[virq] = irq;
     }
 
     irq_bindcount[irq]++;
@@ -169,7 +174,8 @@ int bind_virq_to_irq(int virq)
 void unbind_virq_from_irq(int virq)
 {
     evtchn_op_t op;
-    int irq    = virq_to_irq[virq];
+    int cpu    = smp_processor_id();
+    int irq    = per_cpu(virq_to_irq, cpu)[virq];
     int evtchn = irq_to_evtchn[irq];
 
     spin_lock(&irq_mapping_update_lock);
@@ -184,12 +190,48 @@ void unbind_virq_from_irq(int virq)
 
         evtchn_to_irq[evtchn] = -1;
         irq_to_evtchn[irq]    = -1;
-        virq_to_irq[virq]     = -1;
+        per_cpu(virq_to_irq, cpu)[virq]     = -1;
+    }
+
+    spin_unlock(&irq_mapping_update_lock);
+}
+
+void bind_ipi_on_cpu(int cpu, int ipi)
+{
+    evtchn_op_t op;
+
+    spin_lock(&irq_mapping_update_lock);
+
+    if (per_cpu(ipi_to_evtchn, cpu)[ipi] == 0) {
+        op.cmd                 = EVTCHNOP_bind_ipi;
+        op.u.bind_ipi.ipi_edom = cpu;
+        if ( HYPERVISOR_event_channel_op(&op) != 0 )
+            panic("Failed to bind virtual IPI %d on cpu %d\n", ipi, cpu);
+
+        per_cpu(ipi_to_evtchn, cpu)[ipi] = op.u.bind_ipi.port;
     }
 
     spin_unlock(&irq_mapping_update_lock);
 }
 
+void unbind_ipi_on_cpu(int cpu, int ipi)
+{
+    evtchn_op_t op;
+    int evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi];
+
+    spin_lock(&irq_mapping_update_lock);
+
+    op.cmd          = EVTCHNOP_close;
+    op.u.close.dom  = DOMID_SELF;
+    op.u.close.port = evtchn;
+    if ( HYPERVISOR_event_channel_op(&op) != 0 )
+       panic("Failed to unbind virtual IPI %d on cpu %d\n", ipi, cpu);
+
+    per_cpu(ipi_to_evtchn, cpu)[ipi] = 0;
+
+    spin_unlock(&irq_mapping_update_lock);
+}
+
 int bind_evtchn_to_irq(int evtchn)
 {
     int irq;
@@ -414,6 +456,11 @@ static struct irqaction misdirect_action = {
     NULL
 };
 
+void setup_misdirect_virq(void)
+{
+    (void)setup_irq(bind_virq_to_irq(VIRQ_MISDIRECT), &misdirect_action);
+}
+
 static irqreturn_t xen_dbg(int irq, void *dev_id, struct pt_regs *regs)
 {
      char *msg = "debug\n";
@@ -433,11 +480,12 @@ static struct irqaction xen_action = {
 void irq_suspend(void)
 {
     int pirq, virq, irq, evtchn;
+    int cpu = smp_processor_id(); /* XXX */
 
     /* Unbind VIRQs from event channels. */
     for ( virq = 0; virq < NR_VIRQS; virq++ )
     {
-        if ( (irq = virq_to_irq[virq]) == -1 )
+        if ( (irq = per_cpu(virq_to_irq, cpu)[virq]) == -1 )
             continue;
         evtchn = irq_to_evtchn[irq];
 
@@ -457,13 +505,14 @@ void irq_resume(void)
 {
     evtchn_op_t op;
     int         virq, irq, evtchn;
+    int cpu = smp_processor_id(); /* XXX */
 
     for ( evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++ )
         mask_evtchn(evtchn); /* New event-channel space is not 'live' yet. */
 
     for ( virq = 0; virq < NR_VIRQS; virq++ )
     {
-        if ( (irq = virq_to_irq[virq]) == -1 )
+        if ( (irq = per_cpu(virq_to_irq, cpu)[virq]) == -1 )
             continue;
 
         /* Get a new binding from Xen. */
@@ -485,12 +534,14 @@ void irq_resume(void)
 void __init init_IRQ(void)
 {
     int i;
+    int cpu;
 
     spin_lock_init(&irq_mapping_update_lock);
 
     /* No VIRQ -> IRQ mappings. */
-    for ( i = 0; i < NR_VIRQS; i++ )
-        virq_to_irq[i] = -1;
+    for ( cpu = 0; cpu < NR_CPUS; cpu++ )
+       for ( i = 0; i < NR_VIRQS; i++ )
+           per_cpu(virq_to_irq, cpu)[i] = -1;
 
     /* No event-channel -> IRQ mappings. */
     for ( i = 0; i < NR_EVENT_CHANNELS; i++ )
@@ -525,7 +576,7 @@ void __init init_IRQ(void)
         irq_desc[pirq_to_irq(i)].handler = &pirq_type;
     }
 
-    (void)setup_irq(bind_virq_to_irq(VIRQ_MISDIRECT), &misdirect_action);
+    (void)setup_misdirect_virq();
 
     printk("debug_int\n");
        (void)setup_irq(bind_virq_to_irq(VIRQ_DEBUG), &xen_action);
index 270dbcecb4ea8a4aa4fe316c0c9890c217d01081..d1dbc042c26e58742d41ec00d820cdda0a91c280 100644 (file)
 /* Dynamic binding of event channels and VIRQ sources to Linux IRQ space. */
 extern int  bind_virq_to_irq(int virq);
 extern void unbind_virq_from_irq(int virq);
+extern int  bind_ipi_on_cpu(int cpu, int ipi);
+extern void unbind_ipi_on_cpu(int cpu, int ipi);
 extern int  bind_evtchn_to_irq(int evtchn);
 extern void unbind_evtchn_from_irq(int evtchn);
 
index f3a242ea2ea9d2107f42cb7c9b7ba2fb8b68a12a..6ada9f3e28d653879b64bf7f68dad71d8d53c462 100644 (file)
@@ -270,6 +270,33 @@ static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
         return port;
 
     bind->port = port;
+    printk("evtchn_bind_virq %d/%d virq %d -> %d\n",
+           d->id, ed->eid, virq, port);
+    return 0;
+}
+
+static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind)
+{
+    struct exec_domain *ed = current;
+    struct domain *d = ed->domain;
+    int            port, ipi_edom = bind->ipi_edom;
+
+    spin_lock(&d->event_channel_lock);
+
+    if ( (port = get_free_port(d)) >= 0 )
+    {
+        d->event_channel[port].state      = ECS_IPI;
+        d->event_channel[port].u.ipi_edom = ipi_edom;
+    }
+
+    spin_unlock(&d->event_channel_lock);
+
+    if ( port < 0 )
+        return port;
+
+    bind->port = port;
+    printk("evtchn_bind_ipi %d/%d ipi_edom %d -> %d\n",
+           d->id, current->eid, ipi_edom, port);
     return 0;
 }
 
@@ -307,6 +334,8 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
         return rc;
 
     bind->port = port;
+    printk("evtchn_bind_pirq %d/%d pirq %d -> port %d\n",
+           d->id, current->eid, pirq, port);
     return 0;
 }
 
@@ -352,6 +381,9 @@ static long __evtchn_close(struct domain *d1, int port1)
                 ed->virq_to_evtchn[chn1[port1].u.virq] = 0;
         break;
 
+    case ECS_IPI:
+        break;
+
     case ECS_INTERDOMAIN:
         if ( d2 == NULL )
         {
@@ -516,6 +548,10 @@ static long evtchn_status(evtchn_status_t *status)
         status->status = EVTCHNSTAT_virq;
         status->u.virq = chn[port].u.virq;
         break;
+    case ECS_IPI:
+        status->status     = EVTCHNSTAT_ipi;
+        status->u.ipi_edom = chn[port].u.ipi_edom;
+        break;
     default:
         BUG();
     }
@@ -555,6 +591,12 @@ long do_event_channel_op(evtchn_op_t *uop)
             rc = -EFAULT; /* Cleaning up here would be a mess! */
         break;
 
+    case EVTCHNOP_bind_ipi:
+        rc = evtchn_bind_ipi(&op.u.bind_ipi);
+        if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
+            rc = -EFAULT; /* Cleaning up here would be a mess! */
+        break;
+
     case EVTCHNOP_bind_pirq:
         rc = evtchn_bind_pirq(&op.u.bind_pirq);
         if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
index b50e01861b955e4bcf42df83d6604c3f44ff1e36..56be7749b18f380aa30a0bf11239074c29a332f9 100644 (file)
@@ -107,15 +107,14 @@ void do_task_queues(unsigned char key)
                    ed->ed_flags,
                    ed->vcpu_info->evtchn_upcall_pending, 
                    ed->vcpu_info->evtchn_upcall_mask);
+            printk("Notifying guest... %d/%d\n", d->id, ed->eid); 
+            printk("port %d/%d stat %d %d %d\n",
+                   VIRQ_DEBUG, ed->virq_to_evtchn[VIRQ_DEBUG],
+                   test_bit(ed->virq_to_evtchn[VIRQ_DEBUG], &d->shared_info->evtchn_pending[0]),
+                   test_bit(ed->virq_to_evtchn[VIRQ_DEBUG], &d->shared_info->evtchn_mask[0]),
+                   test_bit(ed->virq_to_evtchn[VIRQ_DEBUG]>>5, &ed->vcpu_info->evtchn_pending_sel));
+            send_guest_virq(ed, VIRQ_DEBUG);
         }
-        ed = d->exec_domain[0];
-        printk("Notifying guest... %d/%d\n", d->id, ed->eid); 
-        printk("port %d/%d stat %d %d %d\n",
-               VIRQ_DEBUG, ed->virq_to_evtchn[VIRQ_DEBUG],
-               test_bit(ed->virq_to_evtchn[VIRQ_DEBUG], &d->shared_info->evtchn_pending[0]),
-               test_bit(ed->virq_to_evtchn[VIRQ_DEBUG], &d->shared_info->evtchn_mask[0]),
-               test_bit(ed->virq_to_evtchn[VIRQ_DEBUG]>>5, &ed->vcpu_info->evtchn_pending_sel));
-        send_guest_virq(d->exec_domain[0], VIRQ_DEBUG);
     }
 
     read_unlock(&domlist_lock);
index 284326d9b69eeb93a1c42d63d621e11bc58e45c5..8d1025ff298e00a8374e132881a013091e46fd96 100644 (file)
@@ -128,6 +128,7 @@ typedef struct {
 #define EVTCHNSTAT_interdomain  2  /* Channel is connected to remote domain. */
 #define EVTCHNSTAT_pirq         3  /* Channel is bound to a phys IRQ line.   */
 #define EVTCHNSTAT_virq         4  /* Channel is bound to a virtual IRQ line */
+#define EVTCHNSTAT_ipi          5  /* Channel is bound to a virtual IPI line */
     u32     status;                   /*  8 */
     union {                           /* 12 */
         struct {
@@ -140,9 +141,22 @@ typedef struct {
         } PACKED interdomain; /* EVTCHNSTAT_interdomain */
         u32 pirq;      /* EVTCHNSTAT_pirq        */   /* 12 */
         u32 virq;      /* EVTCHNSTAT_virq        */   /* 12 */
+        u32 ipi_edom;  /* EVTCHNSTAT_ipi         */   /* 12 */
     } PACKED u;
 } PACKED evtchn_status_t; /* 20 bytes */
 
+/*
+ * EVTCHNOP_bind_ipi: Bind a local event channel to receive events.
+ */
+#define EVTCHNOP_bind_ipi         7
+typedef struct {
+    /* IN parameters. */
+    u32 ipi_edom;                     /*  0 */
+    /* OUT parameters. */
+    u32 port;                         /*  4 */
+} PACKED evtchn_bind_ipi_t; /* 8 bytes */
+
+
 typedef struct {
     u32 cmd; /* EVTCHNOP_* */         /*  0 */
     u32 __reserved;                   /*  4 */
@@ -154,6 +168,7 @@ typedef struct {
         evtchn_close_t            close;
         evtchn_send_t             send;
         evtchn_status_t           status;
+        evtchn_bind_ipi_t         bind_ipi;
         u8                        __dummy[24];
     } PACKED u;
 } PACKED evtchn_op_t; /* 32 bytes */
index 8eb1ed015abbee3f7299928ee688863707a1f069..63eafa4204843035269890e44417cbd055653270 100644 (file)
@@ -36,6 +36,7 @@ typedef struct event_channel_st
 #define ECS_INTERDOMAIN  2 /* Channel is bound to another domain.            */
 #define ECS_PIRQ         3 /* Channel is bound to a physical IRQ line.       */
 #define ECS_VIRQ         4 /* Channel is bound to a virtual IRQ line.        */
+#define ECS_IPI          5 /* Channel is bound to a virtual IPI line.        */
     u16 state;
     union {
         struct {
@@ -47,6 +48,7 @@ typedef struct event_channel_st
         } __attribute__ ((packed)) interdomain; /* state == ECS_INTERDOMAIN */
         u16 pirq; /* state == ECS_PIRQ */
         u16 virq; /* state == ECS_VIRQ */
+        u32 ipi_edom; /* state == ECS_IPI */
     } u;
 } event_channel_t;